
;--- implements API translation for Int 21h

	.386

	include hdpmi.inc
	include external.inc

_LTRACE_ = 0

	option proc:private

?OPTIMIZETLBCOPY = 1	;dont copy to TLB if src/dst is in dos memory already
ifndef ?LFNSUPPORT
?LFNSUPPORT      = 1	;std=1: support LFN API translation
endif

SIZE_BY_HANDLE_FILE_INFO equ 7*4 + 3*8

;--- the structure of the EXEC parameter block
;--- is not documented anywhere. It is the one
;--- used by Win9x, WinXP, DPMIONE and 32RTM.
;--- For 32bit there is *no* environment segment
;--- and the cmdline pointer is a QWORD.

if ?32BIT

EXECPM struct
cmdline dq ?
fcb1	dq ?
fcb2	dq ?
EXECPM ends

else

EXECPM struct
environ dw ?
cmdline dd ?
fcb1	dd ?
fcb2	dd ?
EXECPM ends

endif

EXECRM struct
environ dw ?
cmdline dd ?
fcb1	dd ?
fcb2	dd ?
res1	dd ?
res2	dd ?
EXECRM ends

if ?INT21API

	@seg CONST32

_DATA16 segment

?DPBSIZE = 33	  ;DOS 4+, (DOS 3.XX 32 Bytes)

if ?SUPPDOS33
	public wDPBSize
wDPBSize	dw ?DPBSIZE
endif

;--- used by int 21h, ah=4Bh
execparm  EXECRM <0,120h,100h,110h,0,0>

_DATA16 ends

_TEXT32 segment

CONST32 segment
dummyfcb label byte
	db 0
	db 11 dup (' ')
	db 4 dup (0)
dummycmd db 0,cr
CONST32 ends

;*** entry dos api translation
;--- DOS might indicate success not only with CF, but sometimes
;--- with ZF. So retf2exit has to be used!

	@ResetTrace

intr21 proc public

ife ?FASTINT21
	push offset retf2exit
else
	cmp word ptr [esp].IRET32.rCS, _CSSEL_	;is it an internal call?
	jz intr21_ 								;then dont route to ring 3
	cmp word ptr cs:int21vec._Cs,_INTSEL_	;vector modified?
	jz intr21_
	@simintpms 21
	align 4
endif
intr21 endp

intr21_ proc public
if _LTRACE_
	push offset protaftercall
endif
	cld
if ?32BIT
	@dprintf "i21 bc: a-d=%X %lX %lX %lX ds=%lX es=%lX",\
		ax,ebx,ecx,edx,ds,es
;	@waitesckey
else
	@dprintf "i21 bc: a=%X b=%X c=%X d=%X si=%X di=%X ds=%lX es=%lX",\
		ax,bx,cx,dx,si,di,ds,es
endif
if ?FASTINT21
	push offset retf2exit
endif
	cmp ah,74h
	jnb @F
	push ebx
	movzx ebx,ah
	push cs:[ebx*4+offset jmptab]
	mov ebx,[esp+4]
	retn 4
	align 4
@@:
	call setdsreg2tlb
	call setesreg2tlb		 ;just to be sure set DS+ES=TLB
	jmp rmdos
	align 4
intr21_ endp

if _LTRACE_
protaftercall:
	@dprintf "#i21 ac: a-d=%X %X %X %X si=%X di=%X %lX %lX", ax, bx, cx, dx, si, di, ds, es
	pushf
	@dprintf <" fl=%X",lf>
;	@waitesckey
	ret
	align 4
endif

;--- DOS jump table macros

@tabentry macro function
	ifnb <function>
	 dd offset function
	else
	 dd offset rmdos
	endif
endm

@do macro a,b,c,d
	@tabentry a
	@tabentry b
	@tabentry c
	@tabentry d
endm

CONST32 segment

jmptab label dword
	@do intr2100   ,		   ,		   ,		   ;00-03
	@do 		   ,		   ,		   ,		   ;04-07
	@do 		   ,intr2109   ,intr210A   ,		   ;08-0B
	@do intr210C   ,		   ,		   ,unsuppcall ;0C-0F
	@do unsuppcall ,intr2111   ,intr2112   ,intr2113   ;10-13
	@do unsuppcall ,unsuppcall ,unsuppcall ,unsuppcall ;14-17
	@do 		   ,		   ,intr211A   ,intr211B   ;18-1B
	@do intr211C   ,		   ,		   ,intr211F   ;1C-1F
	@do 		   ,unsuppcall ,unsuppcall ,unsuppcall ;20-23
	@do unsuppcall ,intr2125   ,		   ,unsuppcall ;24-27
	@do unsuppcall ,intr2129   ,		   ,		   ;28-2B
	@do 		   ,		   ,		   ,intr212F   ;2C-2F
	@do 		   ,		   ,intr2132   ,		   ;30-33
	@do intr2134   ,intr2135   ,		   ,		   ;34-37
	@do intr2138   ,intr2139   ,intr213A   ,intr213B   ;38-3B
	@do intr213C   ,intr213D   ,		   ,intr213F   ;3C-3F
	@do intr2140   ,intr2141   ,		   ,intr2143   ;40-43
	@do subsys44   ,		   ,		   ,intr2147   ;44-47
	@do intr2148   ,intr2149   ,intr214A   ,intr214B   ;48-4B
	@do intr214C   ,		   ,intr214E   ,intr214F   ;4C-4F
	@do intr2150   ,intr2151   ,intr2152   ,intr2153   ;50-53
	@do 		   ,intr2155   ,intr2156   ,		   ;54-57
	@do 		   ,intr2159   ,intr215A   ,intr215B   ;58-5B
	@do 		   ,subsys5d   ,subsys5e   ,		   ;5C-5F
	@do intr2160   ,		   ,intr2162   ,intr2163   ;60-63
	@do 		   ,intr2165   ,		   ,		   ;64-67
	@do 		   ,intr2169   ,		   ,		   ;68-6B
	@do intr216C   ,		   ,		   ,		   ;6C-6F
	@do 		   ,intr2171   ,		   ,intr2173   ;70-73
CONST32 ends

	@ResetTrace

else ;?INT21API
_TEXT32 segment
intr21 proc public
	cmp ah,4Ch
	jz _exitclient_pm
	push offset retf2exit
intr21 endp
endif

rmdos proc public
	@dprintf "enter rmdos call ax=%X,bx=%X,cx=%X,dx=%X",ax,bx,cx,dx
	@simrmint 21h
	ret
	align 4
rmdos endp

;--- internal dos call. make sure DS+ES do not contain ring 0 selectors

rmdosintern proc public
	push ds
	push es
	push 0
	pop ds
	push 0
	pop es
	call rmdos
	pop es
	pop ds
	ret
	align 4
rmdosintern endp

if ?INT21API

intr214C:
	jmp _exitclient_pm

;*** function 00: kill psp
;--- this terminates the current psp
;--- that is:
;--- + close open files
;*** + activate parent psp at PSP:[0016h]. may be a segment or selector.
;*** unlike the real-mode version this function returns to the caller,
;*** (and the MCB of the PSP is *not* freed???)
;*** to achieve this goal the int 22h vector in the current psp
;*** is set to an address which returns to protected mode. In real-mode
;*** an int 21h, ah=4Ch function is executed.

	@ResetTrace
;_LTRACE_ = 1

	assume es:SEG16

intr2100:
	@dprintf "i21,00: entry ebx=%lX esi=%lX edi=%lX ebp=%lX",ebx,esi,edi,ebp
	pushad
	push es

	push byte ptr _FLATSEL_
	pop es
	mov eax,ss:[dwSDA]
	movzx ebx,word ptr es:[eax].DOSSDA.wPSP	;get current psp in bx
	shl ebx,4

;ife ?32BIT	;tried 16-bit only in v3.18, but has problems!
if 1

;--- someone (Win31!) may have converted the parent psp segment to a
;--- selector, but now real-mode DOS will use it (and expect a segment
;--- value); so check if it is really a selector to a valid PSP
;--- and if true, transform it back to a segment

	mov ax,es:[ebx+16h]
	@dprintf "i21,00: curr psp linear addr=%lX, parent psp=%X",ebx,ax

	verw ax			;is a valid data selector?
	jnz @F
	push ds
	mov ds,eax
	cmp word ptr ds:[0],20CDh	;points to a PSP?
	pop ds
	jnz @F
	push eax
	call sel2segm
	pop eax
	jc @F
	mov es:[ebx+16h],ax
@@:
endif

	@dprintf "i21,00: simulating i21, ax=4C00, [psp+18]=%lX, [psp-0F]=%X, esp=%lX", dword ptr es:[ebx+18h], word ptr es:[ebx-0Fh], esp
	mov ax, ss:[wHostSeg]
	shl eax,16
	mov ax,offset rm_exit
	mov es:[ebx+000Ah], eax
	mov ax,4C00h
if _LTRACE_
	push ebx
endif
	call rmdos
if _LTRACE_
	pop ebx
endif
	@dprintf "i21,00: back from real mode, ebx=%lX [psp+18]=%lX [psp-0F]=%X esp=%lX", ebx, dword ptr es:[ebx+18h], word ptr es:[ebx-0Fh], esp

	@dprintf "i21,00: exit ebx=%lX esi=%lX edi=%lX ebp=%lX",ebx,esi,edi,ebp
	pop es
	popad
	ret
pm_exit:
	ret 4
_TEXT16 segment
rm_exit:
	@jmp_pmX pm_exit
_TEXT16 ends
	align 4

ife ?DTAINHOSTPSP
getDTA proc
	pushad
	mov ah,2Fh
	call rmdos
	movzx eax, ss:v86iret.rES
	shl eax, 4
	movzx ebx, bx
	add eax, ebx
	mov ss:[dwDTA], eax
	popad
	ret
	align 4
getDTA endp
endif

;*** set DTA (in DS:EDX) ***

	@ResetTrace

intr211A proc
if ?32BIT
	@dprintf "i21: dta set to %lX:%lX",ds,edx
	mov dword ptr ss:[dtaadr+0],edx
else
	@dprintf "i21: dta set to %lX:%X",ds,dx
	mov word ptr ss:[dtaadr+0],dx
endif
	mov word ptr ss:[dtaadr+4],ds
if ?DTAINHOSTPSP
	push edx
	call resetdta
	pop edx
else
	call getDTA	;this is needed!
endif
	ret
	align 4
intr211A endp

;*** get DTA (in ES:E/BX) ***

	@ResetTrace

intr212F proc
	mov bx,word ptr ss:[dtaadr+4]
	verr bx
	jz @F
	@dprintf "i21: error - dta selector %X is invalid",bx
if ?32BIT
	xor ebx,ebx
	mov dword ptr ss:[dtaadr+0],ebx
else
	xor bx,bx
	mov word ptr ss:[dtaadr+0],bx
	mov word ptr ss:[dtaadr+2],bx
endif
	mov word ptr ss:[dtaadr+4],bx
@@:
ife ?DTAINHOSTPSP
	call getDTA
endif
if ?32BIT
	les ebx,fword ptr ss:[dtaadr]
	@dprintf "i21: dta get (%lX:%lX)",es,ebx
else
	mov bx,word ptr ss:[dtaadr+0]
	mov es,word ptr ss:[dtaadr+4]
	@dprintf "i21: dta get (%lX:%X)",es,bx
endif
	ret
	align 4
intr212F endp

	@ResetTrace

;--- get Interrupt vector in ES:E/BX

intr2135 proc
	push eax
	push ecx
	push edx
	mov bl,al
	mov ax,0204h
	@int_31
	mov es,ecx
if ?32BIT
	mov ebx,edx
else
	mov bx,dx
endif
	pop edx
	pop ecx
	pop eax
	ret
	align 4
intr2135 endp

;*** set interrupt vector DS:E/DX ***

intr2125 proc
	pushad
	mov ecx,ds
	mov bl,al
	mov ax,0205h
	@int_31
	popad
	ret
	align 4
intr2125 endp

;-------------------------------------------------
;--- alloc memory: e/bx = size in paragraphs
;--- bx=ffffh (16-bit) or ebx >= 10000000h (32-bit): return available free mem

	@ResetTrace

intr2148 proc
	pushad
if ?32BIT
	@dprintf "I21, ah=48h: alloc %lX paragraphs",ebx
	test ebx, 0F0000000h		;4 GB limit is 0FFFFFFFh paragraphs
	jnz error8
else
	@dprintf "I21, ah=48h: alloc %X paragraphs",bx
	cmp bx,-1
	jz error8
	movzx ebx,bx
endif
	shl ebx,4 	;paragraphs -> bytes
	mov ebp, ebx
	push ebx
	pop cx
	pop bx
	mov ax,0501h
	@int_31
	jc error8
	@dprintf "I21: memory alloc successfull, Addr=%lX",bx,cx
	push ebp		;2. argument for desc_alloc: size
	push bx
	push cx			;1. argument for desc_alloc: address
	call desc_alloc
	jc error2
	@dprintf "I21: selector tiling successfull, sel=%X",ax
	mov [esp].PUSHADS.rAX, ax
	popad
	ret
error2:
	mov ax,0502h	;free memory block SI:DI
	@int_31
error8:
	popad
	jmp   availparas
	align 4
intr2148 endp

	@ResetTrace

;*** free DOS memory block in ES
;*** ES is cleared
;--- ds as well if ds == es

intr2149 proc		;DOS free memory
	pushad
	mov ebx, es
	@dprintf "free dos mem block %X", bx
	mov ax, 6
	@int_31
	jc error9
	@dprintf "linear address dos memory block=%lX",cx,dx
	test cx,0FFF0h	;is it conventional memory?
	jnz isextmem
	mov edx, ebx
	mov ax,0101h
	@int_31
	popad
	ret
isextmem:
	mov esi,ecx	;handle is equal to base in HDPMI
	mov edi,edx
	mov ax,0502h
	@int_31
	jc error9
	mov edx,es
	call desc_free
	popad
	ret
error9:
	popad
	mov ax,9
	stc
	ret
	align 4
intr2149 endp

;--- return C, ax=8, E/BX=available paragraphs

availparas proc
	push ds
	pushad
	push ss
	pop ds
	call pm_GetNumPhysPages
	sub eax, ecx
	shl eax,8			;pages -> paras
if ?32BIT
	mov [esp].PUSHADS.rEBX,eax
else
	cmp eax,0FFFFh
	jc @F
	mov ax,0FFFEh		;5.6.2004: changed from FFF0h
@@:
	mov [esp].PUSHADS.rBX,ax
endif
	popad
	pop ds
	mov ax,8			;not enough memory
	stc
	ret
	align 4
availparas endp

	@ResetTrace

;--- int 21h, ah=4A, resize memory block
;--- block in ES, new size in E/BX

intr214A proc

	pushad
	@dprintf "memselresize: es=%lX, ebx=%lX", es, ebx
	mov ebx, es
	mov ax, 6
	@int_31
	jc error9
	@dprintf "memselresize: selector is valid"
	test cx,0FFF0h	;is it conventional memory?
	jnz isextmem
	mov edx, ebx
	mov ebx, [esp].PUSHADS.rEBX
	mov ax,0102h
	@int_31
	jc @F
	popad
	ret
@@:
	mov word ptr [esp].PUSHADS.rEAX,ax
	mov word ptr [esp].PUSHADS.rEBX,bx
	popad
	ret
isextmem:
	mov esi,ecx	;handle is base in HDPMI
	mov edi,edx
if ?32BIT
	mov ebx, [esp].PUSHADS.rEBX
	test ebx, 0F0000000h
	jnz error8
else
	movzx ebx, [esp].PUSHADS.rBX
endif
	shl ebx,4			;paras -> bytes
ife ?32BIT
	mov edx,es
	call desc_avail		;check if enough free LDT descriptors are available
	jc error8			;to map the new size of the block
endif
	push ebx
	pop cx
	pop bx
	mov ax,0503h
	@int_31
	jc error8
	@dprintf "memselresize: resizemem succeeded, base=%lX",cx,bx
	mov edx, ecx
	mov ecx, ebx
	mov ebx, es
	mov ax, 7 			;set segment base
	@int_31
	@dprintf "memselresize: base set for %X", es
if ?32BIT
	mov eax, [esp].PUSHADS.rEBX
else
	movzx eax, [esp].PUSHADS.rBX
endif
	shl eax, 4
	mov edx, es
	call desc_resize	;adjust selector array (should not fail)
	jc error8			;out of selectors! (16bit only)
	popad
	ret
error9:
	popad
	mov ax,9
	ret
error8:
	popad
	jmp availparas

	align 4
intr214A endp

;-------------------------------------------------------------
resetdta proc public
if ?DTAINHOSTPSP
	mov dx,ss:[wHostPSP]
	mov ss:v86iret.rDS,dx
	mov dx,0080h
	mov ah,1Ah
	jmp rmdos
else
	call getDTA
	ret
endif
	align 4
resetdta endp

	@ResetTrace

;--- int 21h, ah=4Bh
;--- preserves all registers except AX

intr214B proc
	cmp al,0	; v3.20: try to translate ax=4B00h only
	jnz rmdos
	pushad
	push ds
	push es
if ?32BIT
	@dprintf "#I21: ax=%X ds:edx=%lX:%lX, es:ebx=%lX:%lX",ax,ds,edx,es,ebx
	@dprintf "   cmdl=%X:%lX", word ptr es:[ebx].EXECPM.cmdline+4, dword ptr es:[ebx].EXECPM.cmdline+0
	@dprintf " fcb1=%X:%lX", word ptr es:[ebx].EXECPM.fcb1+4, dword ptr es:[ebx].EXECPM.fcb1+0
	@dprintf <" fcb2=%X:%lX",lf>, word ptr es:[ebx].EXECPM.fcb2+4, dword ptr es:[ebx].EXECPM.fcb2+0
	push dword ptr es:[ebx].EXECPM.cmdline+4
	push dword ptr es:[ebx].EXECPM.cmdline+0
	push dword ptr es:[ebx].EXECPM.fcb2+4
	push dword ptr es:[ebx].EXECPM.fcb2+0
	push dword ptr es:[ebx].EXECPM.fcb1+4
	push dword ptr es:[ebx].EXECPM.fcb1+0
else
	movzx ebx,bx
	@dprintf "I21: ax=%X ds:dx=%lX:%X, es:bx=%lX:%X",ax,ds,dx,es,bx
	push dword ptr es:[ebx].EXECPM.cmdline
	push dword ptr es:[ebx].EXECPM.fcb2
	push dword ptr es:[ebx].EXECPM.fcb1
endif
	mov cl,2
	movzx ecx,cl
	mov edi,100h	   ;destination is TLB.100h
	push byte ptr _TLBSEL_
	pop es
nextfcb:
if ?32BIT
	pop esi
	pop eax
else
	pop si
	movzx esi, si
	pop ax
endif
	verr ax
	jz @F
	mov esi, offset dummyfcb
	mov eax, cs
@@:
	mov ds,eax
	movsd
	movsd
	movsd
	movsd
	dec cl
	jnz nextfcb
if ?32BIT
	pop esi
	pop eax
else
	pop si
	pop ax
endif
	verr ax
	jz @F
	mov esi, offset dummycmd
	mov eax, cs
@@:
	mov ds,eax
	mov cl,[esi]
	inc cl
	inc cl
	rep movsb

	push ss
	pop ds
	assume ds:GROUP16
	mov ax,[wSegTLB]
	mov word ptr execparm.fcb1+2, ax
	mov word ptr execparm.fcb2+2, ax
	mov word ptr execparm.cmdline+2, ax

	pop es

if ?32BIT
  if 1
	call getrmenv		 ;get current environment
  else
	xor eax,eax
  endif
	mov word ptr execparm.environ,ax
else
	;for 16-bit, environment is included
	;in parameter block. must be a real mode
	;segment, though
	mov bx,es:[bx].EXECPM.environ
	verr bx
	jnz @F
	call bx_sel2segm
	jnc EnvIsValid
@@:
	call getrmenv		;get current environment
	mov bx, ax
EnvIsValid:
	mov word ptr execparm.environ, bx
endif
	pop ds
if ?32BIT
	@dprintf "I21: ah=4Bh ds:edx=%ls",ds,edx
else
	@dprintf "I21: ah=4Bh ds:dx=%s",ds,dx
endif
	call copyz_dsdx_2_tlb	;DS:(E)DX -> tlb:0, dx=0

	mov bx, offset execparm

	mov ax,ss:[wHostSeg]
	mov ss:v86iret.rES, ax

	@dprintf "  ds:dx=%X:%X es:bx=%X:%X [env=%X cmdl=%X:%X]",\
		ss:v86iret.rDS, dx, ss:v86iret.rES, bx, ss:[bx].EXECRM.environ,\
		word ptr ss:[bx].EXECRM.cmdline+2, word ptr ss:[bx].EXECRM.cmdline+0
if _LTRACE_
	push ds
	push byte ptr _TLBSEL_
	pop ds
	@dprintf "[cmdline]=%lX %lX %lX", dword ptr ds:[120h],\
			dword ptr ds:[124h], dword ptr ds:[128h]
	pop ds
endif
;	@waitesckey
	mov eax,[esp].PUSHADS.rEAX
if ?32BIT
	movzx edx, dx
	movzx ebx, bx
	movzx esi, si
	movzx edi, di
endif
	call rmdos
	mov [esp].PUSHADS.rAX,ax
	pushfd
	call resetdta
	popfd
	popad
	ret
	align 4
intr214B endp

	@ResetTrace

intr2155 proc
	push edx
	push ebx
	mov ebx,edx			 ;BX=PSP selector
	call bx_sel2segm		 ;-> segment
	jc psperror
	call setpspsel		 ;save selector in cache
	mov edx,ebx
	pop ebx
	call rmdos
	pop edx
	ret
psperror:
	pop ebx
	pop edx
	ret
;	push _EAERR5_
;	jmp fataldosexit
	align 4
intr2155 endp

	@ResetTrace

intr2150 proc
	@dprintf "I21: ah=50h, bx=%X",bx
	push ebx
	call bx_sel2segm
	jc psperror1
	call rmdos
	pop ebx
	ret
psperror1:
	pop ebx
	ret
;	push _EAERR7_
;	jmp fataldosexit
	align 4
intr2150 endp

	@ResetTrace

intr2147 proc
	call setdsreg2tlb	;set v86-ds to TLB
	push esi
	xor esi,esi
	call rmdos
	pop esi
	jc @F
	call copyz_tlb_2_dssi
@@:
	ret
intr2147 endp

intr210C:
	cmp al,0Ah			;only translate the buffered input
	jnz rmdos

intr210A proc
	push ecx
	push edx
ife ?32BIT
	movzx edx,dx
endif
	mov cl,[edx]
	mov ch,00
	inc ecx
	call copy_dsdx_2_tlb ;copy CX bytes to TLB:0
	xor edx,edx
	call rmdos
	pop edx
	push ds
	push byte ptr _TLBSEL_
	pop ds
	mov cl,ds:[0]
	mov ch,0
	pop ds
	inc ecx				;also copy length + 0D
	inc ecx
	call copy_tlb_2_dsdx
@@:
	pop ecx
	ret
	align 4
intr210A endp

;*** 09: write string to stdout ***

intr2109:
	push edx
	call setdsreg2tlb
	call copy$_dsdx_2_tlb
	xor edx,edx
	call rmdos
	pop edx
	ret
	align 4

;*** copy asciiz string from ds:dx to tlb:0
;*** functions:
;*** 39: create dir
;*** 3A: delete dir
;*** 3B: change dir
;*** 3C: create file
;*** 3D: open file
;*** 41: delete file
;*** 43: get file attributes/get compressed file size
;*** 5A: create temp file
;*** 5B: create new file

	@ResetTrace

intr2139:
intr213A:
intr213B:
intr213C:
intr213D:
intr2141:
intr2143:
intr215A:
intr215B:
if ?32BIT
	@dprintf "int 21,ax=%X ds:edx=%ls",ax,ds,edx
else
	@dprintf "int 21,ax=%X ds:dx=%s",ax,ds,dx
endif
	push edx
	call copyz_dsdx_2_tlb
	call rmdos
	pop edx
	ret

	@ResetTrace

;--- Copy country infos (34 bytes) to ds:e/dx.
;--- Some extenders translate the far16 "case map" function address at offset 18 in country info struct.
;--- Win3x/9x doesn't, hdpmi also doesn't.

intr2138 proc
if ?32BIT
	cmp edx,-1		;v3.22: for 32bit, replace dx by edx!
	jz rmdos
else
	cmp dx,-1		;if dx == -1, it is "SET country code", not GET infos
	jz rmdos        ;in that case, AL (and optionally BX) hold the country code
endif
	push edx
	xor edx,edx
	call setdsreg2tlb
	call rmdos
	pop edx
	jc @F
	push ecx
	mov cx,32		;size is 34, but last 10 bytes aren't used
	call copy_tlb_2_dsdx
	pop ecx
	clc
@@:
	ret
intr2138 endp

;--- get/set extended country infos
;---- AL=0 -> get data, al!=0 -> set data
;---- buffer is es:di, cx is size of buffer

	@ResetTrace

intr2165 proc
	@dprintf "int 21,ax=%X es:edi=%X:%lX",ax,es,edi
	and al,al
	jz intr216500
	cmp al,7
	jbe intr21650107
	push eax
	and al,7Fh
	cmp al,21h
	jz intr216521
	cmp al,22h
	pop eax
	jz intr216522
	jmp rmdos
intr21650107:
	push edi
	call setesreg2tlb
	xor edi,edi			;set es:di to TLB:0
	call rmdos
	pop edi
	jc @F
	call copy_tlb_2_esdi	;size has been returned in CX
@@:
	ret
intr216500:					;set country info (ES:E/DI, size CX)
	push edi
	call copy_esdi_2_tlb	;copy cx bytes to tlb, set es to TLB
	xor edi,edi
	call rmdos
	pop edi
	ret
intr216521::					;capitalize string DS:E/DX, size CX
	pop eax
	call copy_dsdx_2_tlb
	push edx
	xor edx,edx
	call rmdos
	pop edx
	jc @F
	call copy_tlb_2_dsdx	;copy CX bytes back to DS:E/DX
@@:
	ret
intr216522:						;capitalize asciiz in DS:E/DX
	push edx
	call copyz_dsdx_2_tlb
	call rmdos
	pop edx
	jc @F
	call copyz_tlb_2_dsdx
@@:
	ret
intr2165 endp

;*** 56: rename file ***
;	  (DS:DX -> ES:DI)

	@ResetTrace

intr2156 proc
	push edi
	push edx
	call copyz_dsdx_2_tlb

	push es
if ?32BIT
	push edi
else
	push word ptr 0
	push di
endif
	mov edi,100h
	push edi
	call copyz_far32_2_tlbxx
	call setesreg2tlb
	call rmdos
	pop edx
	pop edi
	ret
	align 4
intr2156 endp

;*** get true filename ***

intr2160 proc
	push edi
	push esi
	call copyz_dssi_2_tlb	  ;si=0, v86iret.ds=tlb
	call setesreg2tlb
	mov di,100h
	call rmdos
	pop esi
	pop edi
	jc @F
	push es
if ?32BIT
	push edi
else
	push word ptr 0
	push di
endif
	push 100h
	call copyz_tlbxx_2_far32
@@:
	ret
	align 4
intr2160 endp

;*** 6C: open file ***

	@ResetTrace

intr216C proc
 if ?32BIT
	@dprintf "#int 21,ax=%X ds:esi=%ls ", ax, ds, esi
 else
	@dprintf "#int 21,ax=%X ds:si=%s ", ax, ds, si
 endif
	push esi
	call copyz_dssi_2_tlb	   ;si=0,v86iret.ds = tlb
	call rmdos
	pop esi
	@dprintf "ret ax=%X",ax
	ret
	align 4
intr216C endp

;*** 4E: find first entry

intr214E proc
	push edx
	call copyz_dsdx_2_tlb
	call rmdos
	pop edx
	jc @F
	push 43
	call copy_tlbdta_2_dta
@@:
	ret
	align 4
intr214E endp

;*** 4F: find next entry

intr214F proc
	push 43
	call copy_dta_2_tlbdta
	call rmdos
	jc @F
	push 43
	call copy_tlbdta_2_dta
@@:
	ret
intr214F endp


;*** here start the functions which need more complex translation


;*** 29 -> FCB parse ***
;*** DS:E/SI -> asciiz
;--- ES:E/DI -> 37 byte (unopened FCB)

;--- copy string to TLB:0
;--- copy FCB to TLB:100h

;--- after the dos call copy FCB back to es:e/di
;--- and DS:ESI should point at the first byte *not* interpreted!

	@ResetTrace

intr2129 proc
if ?32BIT
	@dprintf "fcb parse with fcb=%lX:%lX, name=%lX:%lX",es,edi,ds,esi
else
	@dprintf "fcb parse with fcb=%lX:%X, name=%lX:%X",es,di,ds,si
endif

	push esi
	push edi

	call copyz_dssi_2_tlb	;sets v86-ds to TLB, si=0

	push es
if ?32BIT
	push edi
else
	push word ptr 0
	push di
endif
	mov edi,100h
	push edi 
	push 37
	call copy_far32_2_tlbxx	;copy 37 bytes to TLB:100h
	call setesreg2tlb

	call rmdos

	pushfd
	movzx esi,si
	add [esp+8],esi		;adjust client ESI
	popfd

	pop edi
	pop esi

	pushfd
	push word ptr 37
	push word ptr 100h
	call copy_tlbxx_2_esdi
	popfd
	ret
	align 4
intr2129 endp

	@ResetTrace

if ?OPTIMIZETLBCOPY

checkfileparams proc
	push eax
if ?32BIT
	lea eax, [ecx+edx]
	cmp eax,010000h+1	;offset + bytes must not exceed 64 kB
	jnc @F
endif
	push ds
	call getlinaddr		;get linear address of DS
	jc @F
	test eax,0FFF00000h
	jnz @F
	shr eax,4
	mov ss:v86iret.rDSd, eax
	@dprintf "no TLB needed for read/write (%lX addr, %X size)",eax,cx
	pop eax
	add esp,4			;dont return
	jmp rmdos
@@:
	pop eax
	ret
	align 4
checkfileparams endp

endif

;*** 3F -> read file BX, (E)CX bytes into DS:(E)DX ***

	@ResetTrace

intr213F proc
if ?OPTIMIZETLBCOPY
	call checkfileparams
endif
	pushad
ife ?32BIT
	movzx edx,dx
	movzx ecx,cx
endif
	mov ebp,?TLBSIZE
	mov si,ss:[wSegTLB]
if ?DYNTLBALLOC
	cmp ecx,ebp
	jbe @F
	call _AllocDosMemory
	jc @F
	mov bp,?DYNTLBSIZE
	shr edi,4
	mov esi,edi
@@:
endif
	@dprintf "start read at %lX:%lX,%lX bytes using %X",ds,edx,ecx,si
	xor edi,edi 	 ;edi is used to count bytes written
nextblock:
	mov eax,[esp].PUSHADS.rEAX
	push ecx
	push edx
	cmp ecx,ebp
	jb @F
	mov ecx,ebp
@@:
	mov ss:v86iret.rDSd,esi
	xor edx,edx
	@dprintf "  call rm dos, read (ax=%X) in TLB (=%X:%X) %X bytes",ax,si,dx,cx
	call rmdos
	pop edx
	pop ecx
	jc intr213FB
	and ax,ax
	jz intr213F_1
	push ecx
	movzx ecx,ax	;copy bytes read to ecx
	add edi,ecx 	;update byte count

	@dprintf "  copying from %X to %lX:%lX %X bytes",si,ds,edx,cx

	invoke copy_flat_2_far32, esi, ds::edx

	add edx,ecx 	 ;now update  ^ buffer pointer

	pop ecx
	cmp ax,bp		 ;if  AX <> BP we're done
	jnz intr213F_1
	sub ecx,ebp
	ja nextblock
intr213F_1:
	clc
if ?32BIT
	mov eax,edi
else
	mov ax,di
endif
intr213FB:
intr213F_er:
if ?32BIT
	mov [esp].PUSHADS.rEAX,eax
else
	mov [esp].PUSHADS.rAX,ax
endif
if ?DYNTLBALLOC
	pushfd
	cmp bp,?TLBSIZE
	jz @F
	call _FreeDosMemory
@@:        
	popfd
endif
	popad
	ret
	align 4
intr213F endp

;*** 40 -> write file BX (E)CX bytes from DS:(E)DX ***

	@ResetTrace

intr2140 proc
if ?OPTIMIZETLBCOPY
	call checkfileparams
endif
	pushad
ife ?32BIT
	movzx edx,dx
	movzx ecx,cx
endif
	mov ebp,?TLBSIZE
	mov si,ss:[wSegTLB]
if ?DYNTLBALLOC
	cmp ecx,ebp
	jbe @F
	call _AllocDosMemory
	jc @F
	mov bp,?DYNTLBSIZE
	shr edi,4
	mov esi,edi
@@:
endif
	@dprintf "start write at %lX:%lX,%lX bytes using %X",ds,edx,ecx,si
	xor edi,edi 	 ;EDI is used to count bytes written
intr2140A:				 ;<----
	mov eax, [esp].PUSHADS.rEAX
	push ecx
	cmp ecx,ebp
	jb @F
	mov ecx,ebp
@@:
	@dprintf "  copying from %lX:%lX to TLB %X bytes",ds,edx,cx

	push edx

	invoke copy_far32_2_flat, esi, ds::edx

	xor edx,edx
	mov ss:v86iret.rDSd,esi
	call rmdos
	pop edx
	pop ecx
	jc fail
	movzx eax,ax	;bytes written
	add edi,eax		;update byte count
	add edx,eax		;update source ptr
	sub ecx,ebp
	ja intr2140A	;if > TLB another loop is required!
	clc
if ?32BIT
	mov eax,edi
else
	mov ax,di
endif
fail:
if ?32BIT
	mov [esp].PUSHADS.rEAX,eax
else
	mov [esp].PUSHADS.rAX,ax
endif
if ?DYNTLBALLOC
	pushfd
	cmp bp,?TLBSIZE
	jz @F
	call _FreeDosMemory
@@:
	popfd
endif
	popad
	ret
	align 4
intr2140 endp

;*** translate bios parameter block to drive parameter block
;*** inp: DS:SI -> bios parameter block
;*** out: ES:BP -> drive parameter block

	@ResetTrace

?BPBSIZE = 36	  ;

intr2153 proc
	push esi
	push edx
	push ecx
	mov edx,esi
	mov cx,?BPBSIZE
	call copy_dsdx_2_tlb
	call setesreg2tlb
	pop ecx
	pop edx
	push ebp
	mov ebp,100h
if 1
	push ds
	push byte ptr _TLBSEL_
	pop ds
	mov word ptr ds:[ebp],0	  ;die ersten 2 bytes werden nicht init.
	pop ds
endif
	mov si,0000
	call rmdos
	pop ebp
	pop esi
        
	pushfd
	push edi
	mov edi, ebp
if ?SUPPDOS33
	push word ptr ss:[wDPBSize]
else
	push word ptr ?DPBSIZE
endif
	push word ptr 100h
	call copy_tlbxx_2_esdi
	pop edi
	popfd
	ret
	align 4
intr2153 endp

;*** Subsystem AH=44h ***

	@ResetTrace

subsys44 proc
	cmp al,2
	jb rmdos	;00/01 ok
	jz f4402
	cmp al,4
	jb f4403
	jz f4404
	cmp al,5
	jz f4405
	cmp al,0Ch
	jb rmdos	;06/07/08/09/0A/0B ok
	jz f440C
	cmp al,0Eh
	jb intr21440D
	jmp rmdos	;0E/0F/10/11 ok

f4402:				;read ioctrl
f4404:				;read ioblock
	push edx
	call copy_dsdx_2_tlb
	xor edx,edx
	call rmdos
	pop edx
	jc @F
	push ecx
	mov ecx,eax
	call copy_tlb_2_dsdx
	pop ecx
@@:
	ret
f4403:				;write ioctrl
f4405:				;write ioblock
	push edx
	call copy_dsdx_2_tlb
	xor edx,edx
	call rmdos
	pop edx
	ret

;*** AX=440Ch (generic character device request) ***

f440C:
	jmp unsuppcall

subsys44 endp

;*** AX=440Dh Subsystem (generic block device request) ***
;*** BL=drive#, CL=minor code ,CH=8 -> fixed disk ***
;*** DOS 3.2+
;*** 40h set device parameters (38+[38]*4+2)
;*** 41h write track
;*** 42h format track
;*** 60h get device parameters (38)
;*** 61h read track
;*** 62h verify track
;*** DOS 4.0+
;*** 46h set volume serial#
;*** 47h set access flag
;*** 66h get volume serial#
;*** 67h get access flag
;*** DOS 5.0+
;*** 68h sense media type
;*** 5xh,7xh -> PCMCIA
;*** DOS 7.0+
;*** 4Ah lock/unlock drive (no translation required)
;--- 6Dh enumerate open files
;--- 6Eh find swap file

	@ResetTrace

intr21440D proc

	@dprintf "I21: call AX=%X,BX=%X,CX=%X,DX=%X",ax,bx,cx,dx
	push esi
	cmp cl,40h
	jnz not440D40
if ?32BIT
	mov ax,[edx+38]
else
	mov si,dx
	mov ax,[si+38]
endif
	shl ax,2
	add ax,38+2
	pop esi
	jmp f440D_ok1
f440D_notrans:
	call setdsreg2tlb	;just to be safe
	mov ax,440Dh
	pop esi
	jmp rmdos
not440D40:
	mov esi,offset tab440D
@@:
	db 2Eh			;CS prefix
	lodsw
	cmp al,-1
;;  jz f440D_er	;why error? in this case just no translation!
	jz f440D_notrans
	cmp al,cl
	jnz @B
	pop esi
	mov al,ah
	mov ah,00
f440D_ok1:
	push ecx
	mov ecx,eax
	@dprintf "I21: func 440d: copy %X bytes to tlb",cx
	call copy_dsdx_2_tlb
	pop ecx
	cmp cl,41h
	jnz @F
	call f440D41b
@@:
	cmp cl,61h
	jnz @F
	call f440D61b
@@:
	call setdsreg2tlb
	push edx
	xor edx,edx
	mov ax,440Dh
	call rmdos
	pop edx
	jc error
	push esi
	mov esi,offset tab440D2
@@:
	cmp byte ptr cs:[esi],-1
	jz f440D2_ok2
	cmp cl,cs:[esi]
	jz f440D2_ok
	inc esi
	inc esi
	jmp @B
f440D2_ok:
	push ecx
	movzx cx,byte ptr cs:[esi+1]
	@dprintf "I21: func 440d: copy %X bytes from tlb",cx
	call copy_tlb_2_dsdx
	pop ecx
f440D2_ok2:
	pop esi
	cmp cl,61h
	jnz @F
	call f440D61a
@@:
	clc
error:
	ret

LOGTRACKPARM struct
special	db ?
head	dw ?
cyl		dw ?
sector	dw ?
numsecs	dw ?
dta		dd ?			;this is a FAR16 address!
LOGTRACKPARM ends

;--- prepare read track. set

f440D61b:
	@dprintf "I21: func 440d,41+61: set transfer buffer to rm"
	push ds
	push byte ptr _TLBSEL_
	pop ds
	push word ptr ss:[wSegTLB]
	push word ptr 0020h
	pop dword ptr ds:[LOGTRACKPARM.dta]
	pop ds
	ret

;--- write track: copy [DS:E/DX+9] -> TLB.20

f440D41b:
	call f440D61b

	pushad					 ;copy track [DS:DX+9] -> TLB
	push ds
	push es
ife ?32BIT
	movzx edx,dx
endif
	movzx ecx,[edx].LOGTRACKPARM.numsecs
	lds si,[edx].LOGTRACKPARM.dta
	movzx esi, si
	shl ecx,9			 ;sectors -> bytes
	@dprintf "I21: func 440d,41: copy %lX bytes to tlb.20",ecx
	push byte ptr _TLBSEL_
	pop es
	mov edi,20h
	rep movsb

	pop es
	pop ds
	popad
	ret
        
;--- read track. copy TLB.20 -> [DS:E/DX+9]

f440D61a:
	pushad
	push ds
	push es
ife ?32BIT
	movzx edx, dx
endif
	movzx ecx,[edx].LOGTRACKPARM.numsecs
	les di,[edx].LOGTRACKPARM.dta
	movzx edi, di
	shl ecx,9			 ;sektors -> bytes
	@dprintf "I21: func 440d,11: copy %X bytes from tlb.20",cx
	push byte ptr _TLBSEL_
	pop ds
	mov esi,20h
	rep movsb

	pop es
	pop ds
	popad
	ret

CONST32 segment
;--- table of int 21h, ax=440D, subfunction CL
;--- bytes to copy from DS:E/DX

tab440D label byte
	db 41h,13
	db 42h,4
	db 46h,25
	db 47h,2
	db 60h,38
	db 61h,13
	db 62h,4
	db 66h,25
	db 67h,2
	db 68h,2
	db -1

;--- table of int 21h, ax=440D, subfunction CL
;--- bytes to copy back to DS:E/DX

tab440D2 label byte
	db 60h,38
	db 61h,13-4
	db 62h,4
	db 66h,25
	db 67h,2
	db 68h,2
;	db 6Dh,255		;enum open files
;	db 6Eh,255		;find swap file path
	db -1h
CONST32 ends

intr21440D endp

;*** Subsystem AH=5Dh - server function call ***

	@ResetTrace

subsys5d proc
	cmp al,6			;get address of SDA?
	jb error			;0,1,2,3,4,5
	jz f5d06			;6
	cmp al,0Ah   		;7,8,9 ist ok
	jb rmdos
	ja error
	push ecx				;0Ah: set extended error info
	mov cx,22
	call copy_dsdx_2_tlb
	pop ecx
	push edx
	xor edx,edx
	call rmdos
	pop edx
	ret
f5d06:
	call rmdos		;get SDA in DS:E/SI
	jmp ds_segm2sel ;no need to clear HIWORD(esi)!
error:
	jmp unsuppcall

subsys5d endp

;*** Subsystem AH=5Eh - network ***

	@ResetTrace

subsys5e proc
	cmp al,0
	jnz rmdos
;;	jz f5e00
f5e00:
	push edx
	call setdsreg2tlb
	xor edx,edx
	push ds
	push byte ptr _TLBSEL_
	pop ds
	mov ds:[0010h],dl
	pop ds
	call rmdos
	pop edx
	jc @F
	push esi
	mov esi,edx
	call copyz_tlb_2_dssi ;copy to DS:(E)SI
	pop esi
@@:
	ret
subsys5e endp

;*** subsystem FCBs 0Fh-17h ***

	@ResetTrace

intr210F:
intr2110:
intr2114:
intr2115:
intr2116:
intr2117:
unsuppcall:
	push 21h
	call unsupp
	stc
	ret
intr2111:
intr2112:
intr2113:					;ds:dx -> fcb
	push ecx
	push edx
	mov cx,0025h			;size of "normal fcb" is 37 bytes
ife ?32BIT
	movzx edx,dx
endif
	cmp byte ptr [edx],0FFh	;extended fcb?
	jnz @F
	mov cl,25h+7			;then size 44 bytes
@@:
	push ecx
	call copy_dsdx_2_tlb 	;copy cx bytes to tlb:0
	xor edx,edx
	call rmdos
	pop ecx
	pop edx
	call copy_tlb_2_dsdx 	;copy back! - may have been modified
	cmp al,0FFh 			;error?
	jz @F
;	@dprintf "I21: fcb call was successful"
	push word ptr 0
	push cx
	call copy_tlbdta_2_dta	;copy cx bytes tlbdta -> dta
@@:
	pop ecx
	ret

;*** 1B: get actual drive info DS:E/BX
;*** 1C: get drive info DS:E/BX
;*** 1F: get DPB for default drive in DS:E/BX
;*** 32: get DPB for drive in DL in DS:E/BX

	@ResetTrace

intr211B:
intr211C:
intr211F:
intr2132:
	@dprintf "I21: ax=%X,dx=%X",ax,dx
	call rmdos
;--- al=FF indicates error, set Carry flag then
	@dprintf "I21: ret, ax=%X, rmDS:bx=%X:%X",ax,ss:v86iret.rDS,bx
	cmp al,0FFh
	jz @F
	call ds_segm2sel
	@dprintf "I21: ds=%X translated to %lX",ss:v86iret.rDS,ds
if ?32BIT
	movzx ebx,bx
endif
	clc
	ret
@@:
	stc
	ret

;*** 34: indos flag (ES:BX) ***
;*** 52: get ListofList (ES:BX) ***

	@ResetTrace

intr2134:
intr2152:
	call rmdos
	call es_segm2sel
if ?32BIT
	movzx ebx,bx
endif
	ret
	align 4

;*** 51: get psp (BX) ***
;*** 62: get psp (BX) ***

intr2151:
intr2162:
	call rmdos
	call getpspsel
	jc pspsel_err
	ret
pspsel_err:
	mov ax,_EAERR6_
	jmp _exitclientEx

;*** get extended error info (ES:DI]
;--- this call may modify v86.rES to 0000

intr2159 proc
	call rmdos
	pushfd
	cmp al,22h		;for this code a pointer is in es:e/di
	jnz @F
	call es_segm2sel
@@:
	popfd
	ret
intr2159 endp

;--- get DBCS table in DS:E/SI

intr2163 proc
	cmp al,0
	jnz rmdos
	call rmdos
;	jc @F				;test for Carry may not work for 21,6300!!!
	pushfd
	cmp al,0
	jnz @F
	call ds_segm2sel
if ?32BIT
	movzx esi,si
endif
@@:
	popfd
	ret
intr2163 endp

;--- get/set disk serial number

intr2169 proc
	push ecx
	mov cx,25
	call intr216521
	pop ecx
	ret
	align 4
intr2169 endp

;*** long filename functions
;*** these arent supported from real mode dos, but
;*** for tracing its good to implement it
;*** and there exist real mode drivers LFNDOS/DOSLFN, which
;*** implements these functions in real dos

	@ResetTrace

if ?LFNSUPPORT

;--- ax=71a7: time conversion functions
;--- bl=0: file time -> dos time; ds:si -> file time (qword)
;---     out: dos time/date in cx/dx
;--- bl=1:  dos time -> file time; cx = dos time; dx = dos date
;---     out: es:di -> file time/date 

int2171a7 proc
	cmp bl,1
	jz @F
	push esi
	call setdsreg2tlb
;--- setup arguments for stdcall copy_far32_2_tlbxx(size:dword, dstofs:dword, src:far32)
;--- v3.23: fixed, must be DS:E/SI, not ES:E/SI
;	push es
	push ds
if ?32BIT
	push esi
else
	push word ptr 0
	push si
endif
	xor esi, esi
	push esi
	push sizeof QWORD
	call copy_far32_2_tlbxx	;copy 8 bytes to TLB:100h
	call rmdoswithcarry
	pop esi
	ret
@@:
	push edi
	call setesreg2tlb
	xor edi, edi
	call rmdoswithcarry
	pop edi
	jc @F
	push word ptr sizeof QWORD ;copy 8 bytes
	push word ptr 0         ;offset TLB
	call copy_tlbxx_2_esdi
@@:
	ret
int2171a7 endp

;--- bh=0 -> ds:edx -> tlb:0
;--- bh=2 -> tlb:0 -> ds:edx
        
int2171aa proc
	@dprintf "int 21,ax=71AA"
	cmp bh,0
	jz copyz_dsdx
	cmp bh,2
	jnz rmdoswithcarry
	push edx
	call setdsreg2tlb
	call rmdoswithcarry
	pop edx
	jc @F
	call copyz_tlb_2_dsdx
@@:
	ret
	align 4
int2171aa endp

;--- int 21, ax=7139 | 713A | 713B | 7141 | 7143        
        
copyz_dsdx proc
if ?32BIT
	@dprintf "int 21,ax=%X ds:edx=%ls",ax,ds,edx
else
	@dprintf "int 21,ax=%X ds:dx=%s",ax,ds,dx
endif
	push edx
	call copyz_dsdx_2_tlb
	call rmdoswithcarry
	pop edx
	ret
	align 4
copyz_dsdx endp


endif

intr2171 proc
if ?LFNSUPPORT
	test ss:[bEnvFlags], ENVF_NOLFN
	jnz unsupp71
	cmp al,39h
	jb rmdoswithcarry
	cmp al,3bh		;39/3a/3b create/remove/change dir
	jbe copyz_dsdx
	cmp al,41h		;delete file
	JZ copyz_dsdx
	cmp al,43h		;get/set file attr
	JZ copyz_dsdx
	cmp al,47h		;get cur dir
	jz int217147
	cmp al,4Eh		;get first file  
	jz int21714e
	cmp al,4Fh		;get next file
	jz int21714f
	cmp al,56h		;rename file
	jz int217156
	cmp al,60h		;get canonical form
	jz int217160
	cmp al,6ch		;create/open file
	jz int21716c
	cmp al,0A0h		;get volume info
	jz int2171a0
	cmp al,0A2h		;same as 714F
	jz int2171a2
	cmp al,0A6h		;get file info by handle
	jz int2171a6
	cmp al,0A7h		;file time to dos time/dos time to file time
	jz int2171a7
	cmp al,0A8h		;generate short filename
	jz int2171a8
	cmp al,0AAh		;subst
	jz int2171aa
	jb rmdoswithcarry
unsupp71:				;A0, A7, A8, A9, AA
	mov al,00
	stc
	ret
	align 4
rmdoswithcarry::
	stc
	jmp rmdos
	align 4

intr2171 endp

;--- int 21, ax=716C (open file)        
;--- translate ds:e/si
        
int21716c proc
if ?32BIT
	@dprintf "int 21,ax=%X ds:esi=%ls",ax,ds,esi
else
	@dprintf "int 21,ax=%X ds:si=%s",ax,ds,si
endif
	push esi
	call copyz_dssi_2_tlb
	call rmdoswithcarry
	pop esi
	ret
	align 4
int21716c endp

;--- int 21, ax=7147 (get cur dir into ds:e/si)        

int217147 proc
	@dprintf "int 21,ax=7147"
	push esi
	xor esi,esi
	call setdsreg2tlb
	call rmdoswithcarry
	pop esi
	jc @F
	call copyz_tlb_2_dssi
@@:
	ret
	align 4
int217147 endp

;--- int 21, ax=7156 (rename file)        
        
int217156 proc
if ?32BIT
	@dprintf "int 21,ax=%X ds:edx=%ls",ax,ds,edx
else
	@dprintf "int 21,ax=%X ds:dx=%s",ax,ds,dx
endif
	push edx
	push edi

	call copyz_dsdx_2_tlb

	push es
if ?32BIT
	push edi
else
	push word ptr 0
	push di
endif
	mov edi,100h
	push edi
	call copyz_far32_2_tlbxx
	call setesreg2tlb
	call rmdoswithcarry

	pop edi
	pop edx
	ret
	align 4
int217156 endp

;--- int 21, ax=714E
;--- DS:E/DX -> file spec
;--- ES:E/DI -> finddata record
;--- SI = date format
;--- CX = attributes

int21714e proc
	push edx
	call copyz_dsdx_ret_esdi
	pop edx
	jc exit
	push word ptr 13eh	;13E = finddata size
	push word ptr 100h	;offset in TLB
	call copy_tlbxx_2_esdi
exit:
	ret
	align 4
int21714e endp

;--- int 21, ax=71A0
;--- DS:E/DX -> [in] root ("C:\")
;--- ES:E/DI -> [out] file system buffer 
;--- CX = [in] size of buffer, [out] max length of file name (usually FFh)
;--- DX = [out] max length of path

int2171a0 proc
	push cx				;size of buffer (2. param copy_tlbxx_2_esdi)
	push word ptr 100h	;offset in TLB (1. param copy_tlbxx_2_esdi)
	call copyz_dsdx_ret_esdi
	jc error
if ?32BIT
	@dprintf "int 21,ax=71A0 ok, es:edi=%lX:%lX, cx=%X",es,edi,cx
else
	@dprintf "int 21,ax=71A0 ok, es:di=%lX:%X, cx=%X",es,di,cx
endif
	call copy_tlbxx_2_esdi
	ret
error:
	add esp,4
	stc
	ret
	align 4
int2171a0 endp

;--- used by ax=714e and 71a0
;--- dont save dx here, dx returns value for 71a0

copyz_dsdx_ret_esdi proc

if ?32BIT
	@dprintf "int 21 ax=%X ds:edx=%ls es:edi=%lX:%lX cx=%X",ax,ds,edx,es,edi,cx
else
	@dprintf "int 21 ax=%X ds:dx=%s es:di=%lX:%X cx=%X",ax,ds,dx,es,di,cx
endif
	push edi
	call copyz_dsdx_2_tlb	;copy ds:dx to TLB:0, set dx=0, v86-ds=TLB
	mov di,100h
	call setesreg2tlb		;es:di = TLB:100h
	call rmdoswithcarry
	pop edi
	ret
	align 4

copyz_dsdx_ret_esdi endp
        
;--- int 21, ax=714F
;--- int 21, ax=71A2

int21714f:
int2171a2:

copy_esdi_ret_esdi proc
	push edi
	push ecx
	mov cx,13Eh
	call copy_esdi_2_tlb
	pop ecx
	xor edi,edi
	call rmdoswithcarry
	pop edi
	jc exit
	push word ptr 13Eh
	push word ptr 0
	call copy_tlbxx_2_esdi
exit:
	ret
copy_esdi_ret_esdi endp

;--- copy asciiz ds:esi to tlb:0, return asciiz from tlb:100h into es:edi
        
int2171a8:
        
;--- int 21, ax=7160 (get canonical form)
;--- DS:E/SI -> path
;--- ES:E/DI -> output buffer
;--- CX = minor code

int217160 proc

if ?32BIT
	@dprintf "int 21 ax=%X ds:esi=%ls es:edi=%lX:%lX",ax,ds,esi,es,edi
else
	@dprintf "int 21 ax=%X ds:si=%s es:di=%lX:%X",ax,ds,si,es,di
endif
	push esi
	push edi
	call copyz_dssi_2_tlb
	mov di,100h
	call setesreg2tlb
	call rmdoswithcarry
	pop edi
	pop esi
	jc exit
	push es
if ?32BIT
	push edi
else
	push word ptr 0
	push di
endif
	push 100h
	call copyz_tlbxx_2_far32
exit:
	ret
int217160 endp

;--- int 21, ax=71A6
;--- return TLB:0 to ds:e/dx

int2171a6 proc
	push edx
	call setdsreg2tlb
	xor edx,edx
	call rmdoswithcarry
	pop edx
	jc exit
	push ecx
	mov cx,SIZE_BY_HANDLE_FILE_INFO
	call copy_tlb_2_dsdx
	pop ecx
exit:
	ret
int2171a6 endp


else					;no LFN support
	mov al,00
	stc
	ret
intr2171 endp

endif

;*** FAT32 support
;*** AL=00:get drive flags (no pointers used)
;*** AL=01:set drive flags (no pointers used)
;*** AL=02:get extended DPB into ES:(E)DI, CX=size of buffer
;*** AL=03:get extended free space into ES:(E)DI, DS:(E)DX is pointer
;*** AL=04:set DPB to use for formatting in ES:(E)DI
;*** AL=05:extended absolute disk read/write, pointer in DS:(E)BX

	@ResetTrace

intr2173 proc

	cmp al,2			;AL=0,1 -> drive locking/flushing
	jc i217300
	cmp al,5
	jz i217305			;AL=5 -> absolute disk read/write FAT32
	jnc i217300
	push edi				;AL=2,3,4
	push edx
	call copy_esdi_2_tlb	;copy CX bytes to TLB:0, rmES=TLB
	cmp al,3
	jnz @F
	push ds				;for ax=7303 DS:E/DX is asciiz ptr
if ?32BIT
	push edx
else
	push word ptr 0
	push dx
endif
	mov edx,100h
	push edx				;offset in tlb
	call copyz_far32_2_tlbxx
	call setdsreg2tlb	;rmDS=TLB
@@:
	xor edi,edi
	call rmdos
	pop edx
	pop edi
	jc @F				;call may also fail with NC if FAT32 isn't
						;implemented, but this shouldn't harm.
	call copy_tlb_2_esdi;copy CX bytes from TLB:0 to ES:E/DI
@@:
	ret
i217300:
i217301:
	call rmdos
	ret
        
;--- FAT32 absolute disk read/write        
;--- AX=7305
;--- CX=FFFF
;--- DL=drive number (01=A,...)
;--- DS:E/BX->io packet (same as for Int 25/26)
;--- SI=flags (bit 0: 0=read, 1=write)

;--- extended disk io structure in real mode

DISKIORM struct
startsec dd ?
sectors  dw ?
buffofs  dw ?
buffseg  dw ?
DISKIORM ends

i217305:
if ?DIO2RMS
	push ss:v86iret.rSS
	pop ss:v86iret.rDS
else
	call setdsreg2tlb
endif
	test si,1
	jnz iswrite
	call PrepareDiskIoRead
	jc @F
	push ebx
if ?DIO2RMS
	mov ebx, ss:v86iret.rESP
	push ebx
	sub ebx, sizeof DISKIORM
	mov ss:v86iret.rESP, ebx
else
	mov bx, 0     ; v3.20: just set BX for real-mode
endif
	call rmdos
if ?DIO2RMS
	pop ss:v86iret.rESP
endif
	pop ebx
	jc @F
	call AfterDiskIoRead
	clc
@@:
	ret
iswrite:
	call PrepareDiskIoWrite
	jc @F
	push ebx
if ?DIO2RMS
	mov ebx, ss:v86iret.rESP
	push ebx
	sub ebx, sizeof DISKIORM
	mov ss:v86iret.rESP, ebx
else
	mov bx, 0     ; v3.20: just set BX for real-mode
endif
	call rmdos
if ?DIO2RMS
	pop ss:v86iret.rESP
endif
	pop ebx
@@:
	ret
intr2173 endp

;--- get current environment as a real mode segment
;--- out: real mode environment in AX

getrmenv proc
	push ebx
	push ds
	push byte ptr _FLATSEL_
	pop ds
	mov ebx, ss:[dwSDA]
	movzx ebx, word ptr [ebx].DOSSDA.wPSP
	shl ebx, 4
	mov bx, [ebx+2ch]
	pop ds
	call bx_sel2segm
	mov ax, bx
	pop ebx
	ret
getrmenv endp

;---------------------------------------------

 if 0

fataldosexit:
	mov ebp,esp
  if ?32BIT
	mov si,[ebp+8]
  else
	mov si,[ebp+6]
  endif
	mov di,[ebp+4]
	@printf <"I21: fatal error (ax=%X bx=%X cx=%X dx=%X cs:ip=%X:%X)",lf>,ax,bx,cx,dx,si,di
	pop eax			;errorcode
;	jmp __exitappx
	jmp _exitclient_pm
 endif

endif	;?INT21API

_TEXT32  ends

end

